package com.topisv.tms.mybatis;

import java.sql.Connection;
import java.util.Map;
import java.util.Properties;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.topisv.tms.utils.PubUtil;

/**
 * mybatis 分页拦截器
 * @author Fisher
 * @version 1.0.0
 */
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class }) })
public class PaginationInterceptor implements Interceptor {
    private Logger logger = LoggerFactory.getLogger(getClass());
    
    /**
     * 翻页拦截器实现 
     * @author Fisher
     * @version 1.0.0
     */
    @SuppressWarnings("rawtypes")
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        MetaObject metaStatementHandler = MetaObject.forObject(statementHandler);
        Map parameterMap = PubUtil.ConvertObjToMap(metaStatementHandler.getValue("delegate.rowBounds"));
        if(parameterMap.get("limit").toString().equals(String.valueOf(RowBounds.NO_ROW_LIMIT)) 
            && parameterMap.get("offset").toString().equals(String.valueOf(RowBounds.NO_ROW_OFFSET))){
            return invocation.proceed(); 
        }
        RowBoundsExt rowBounds = (RowBoundsExt)metaStatementHandler.getValue("delegate.rowBounds");
        if(rowBounds == null){    
            return invocation.proceed();  
        }
        //DefaultParameterHandler defaultParameterHandler = (DefaultParameterHandler)metaStatementHandler.getValue("delegate.parameterHandler");
        //Map parameterMap = DataConvertUtil.ConvertObjToMap(defaultParameterHandler.getParameterObject());
        Object objSidx = parameterMap.get("sidx");
        Object objSord = parameterMap.get("sord");
        String sidx = objSidx != null ? objSidx.toString() : "";
        String sord = objSord != null ? objSord.toString() : "";
        String originalSql = (String)metaStatementHandler.getValue("delegate.boundSql.sql");
        if(PubUtil.isNotEmpty(sidx) && PubUtil.isNotEmpty(sord)){    
            originalSql = originalSql + " order by " + sidx + " " + sord;    
        }
        Configuration configuration = (Configuration)metaStatementHandler.getValue("delegate.configuration");
        DialectType databaseType  = null;
        try{    
            databaseType = DialectType.valueOf(configuration.getVariables().getProperty("dialect").toUpperCase());    
        } catch(Exception e){    
            e.printStackTrace();
        }
        if(databaseType == null){    
            throw new RuntimeException("the value of the dialect property in configuration.xml is not defined : " + configuration.getVariables().getProperty("dialect"));    
        }
        Dialect dialect = null;    
        switch(databaseType){    
            case ORACLE:    
                dialect = new OracleDialect();    
                break;    
            case MYSQL://需要实现MySQL的分页逻辑
                dialect = new MysqlDialect();
                break;    
        }
        metaStatementHandler.setValue("delegate.boundSql.sql", dialect.getLimitString(originalSql,true, rowBounds.getOffset(), rowBounds.getLimit()) );    
        metaStatementHandler.setValue("delegate.rowBounds.offset", RowBounds.NO_ROW_OFFSET );    
        metaStatementHandler.setValue("delegate.rowBounds.limit", RowBounds.NO_ROW_LIMIT );      
        if(logger.isDebugEnabled()){    
            BoundSql boundSql = statementHandler.getBoundSql();    
            logger.debug("生成分页SQL : " + boundSql.getSql());    
        }
        return invocation.proceed(); 
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }
    
    @Override
    public void setProperties(Properties arg0) {
        // TODO Auto-generated method stub
    }
    
}
